﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace EVB.Collections.Immutable.Tests
{
    /// <summary>
    /// This is a test class for Stack_EmptyStackTest and is intended
    /// to contain all Stack_EmptyStackTest Unit Tests
    ///</summary>
    [TestClass]
    public sealed class StackTest
    {
        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #region Additional test attributes

        //
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //

        #endregion

        [TestMethod]
        public void PeekTest()
        {
            const int expected = 17;
            var stack = Stack<int>.Empty.Push(expected);
            int actual = stack.Peek;

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void PopTest()
        {
            var original = new int[] { 5, 2, 1, 7, 4, 5, 3 };
            var expected = (int[])original.Clone();
            Array.Reverse(expected);
            var actual = new List<int>();

            var stack = Stack<int>.Empty;
            foreach (var item in original)
                stack = stack.Push(item);

            for (; !stack.IsEmpty; stack = stack.Pop())
                actual.Add(stack.Peek);

            CollectionAssert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void CountTest()
        {
            const int expected = 2;
            var stack = Stack<int>.Empty.Push(0).Push(0);

            Assert.AreEqual(expected, stack.Count);
        }

        /// <summary>
        /// A test for ToArray()
        ///</summary>
        [TestMethod]
        public void ToArrayTest()
        {
            var stack = Stack<int>.Empty;

            var expected = new int[] { 3, 2, 7, 8 };
            foreach (var item in expected)
                stack = stack.Push(item);
            var actual = stack.ToArray();

            CollectionAssert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void CopyToTest()
        {
            var expected = new int[] { 1, 4, 6, 3, 3 };
            var actual = new int[] { 1, 4, 0, 0, 3 };
            var stack = Stack<int>.Empty.Push(6).Push(3);

            ((System.Collections.ICollection)stack).CopyTo(actual, 2);

            CollectionAssert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ReverseTest()
        {
            var original = new int[] { 5, 1, 6, 2, 11 };
            var expected = new int[] { 11, 2, 6, 1, 5 };

            var stack = Stack<int>.Empty;
            foreach (var item in original)
                stack = stack.Push(item);

            var reversedStack = stack.Reverse();
            var actual = reversedStack.ToArray();

            CollectionAssert.AreEqual(expected, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void EmptyPeekTest()
        {
            var peek = Stack<int>.Empty.Peek;
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void EmptyPopTest()
        {
            var stack = Stack<int>.Empty.Pop();
        }

        [TestMethod]
        public void EmptyCountTest()
        {
            const int expected = 0;
            int actual = Stack<int>.Empty.Count;

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void EmptyToArrayTest()
        {
            var expected = new int[0];
            var actual = Stack<int>.Empty.ToArray();

            CollectionAssert.AreEqual(expected, actual);
        }
    }
}